﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Wicture.DbRESTFul;
using Wicture.DbRESTFul.SQL;
using Wicture.EPC.Common;
using Wicture.EPC.Common.Biz;
using Wicture.EPC.Service.V1.Filters;
using Wicture.EPC.Service.V1.Repository;
using Wicture.EPC.Service.V1.Services.EPC.OnlineQuery;
using Microsoft.Extensions.Logging;
using Wicture.EPC.Service.V1.Models.Volvo;

namespace Wicture.EPC.Service.V1.QueryInterceptors.Interceptors
{
    public class VolvoQueryInterceptor : BaseQueryInterceptor
    {
        private readonly string[] brandCodes = new string[] { "volvo" };

        public override string[] BrandCodes => brandCodes;

        protected override List<Query_PartsResult> GetParts(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke<Query_PartsResult>(CSIs.Query_Parts_For_Volvo, param);
        }
        protected override List<Query_PartsResult> BuildPartResults(List<Query_PartsResult> result)
        {
            if (result != null && result.Any())
            {
                foreach (var item in result)
                {
                    if (!string.IsNullOrEmpty(item.notes))
                    {
                        var notes = item.notes.Split(new char[] { ';' });

                        item.notes = string.Join("$$", notes);
                    }
                    if (!string.IsNullOrEmpty(item.modelNotes))
                    {
                        var applicableModels = item.modelNotes.Split(new char[] { ';' });

                        item.modelNotes = string.Join("$$", applicableModels);
                    }
                }
            }
            return result;
        }
        protected override List<Query_SubGroupResult> BuildSubGroupResults(List<Query_SubGroupResult> result)
        {
            if (result != null && result.Any())
            {
                foreach (var item in result)
                {
                    if (!string.IsNullOrEmpty(item.applicableModel))
                    {
                        var applicableModels = item.applicableModel.Split(new char[] { ';' });

                        item.applicableModel = string.Join("$$", applicableModels);
                    }
                }
            }
            return result;
        }

        protected override void FilterPartsByVin(DbRESTFulRepository repository, ref List<Query_PartsResult> result, string vin, string selectorId)
        {
            if (!result.Any())
            {
                return;
            }
            if (!string.IsNullOrEmpty(vin))
            {
                var vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Volvo, new { vin = vin });
                if (vinInfo != null)
                {
                    Query_SubGroupResult subgroupInfo = repository.Invoke<Query_SubGroupResult>(CSIs.Get_SubGroup_By_ID_For_Volvo, new { id = base._subgroupId });
                    bool subgroupBelongToVin = CheckSubGroupBelongToByApplcableModel(vinInfo, subgroupInfo);
                    foreach (var item in result)
                    {
                        //跳转件
                        if (item.refSubGroupId != null && item.refSubGroupId >= 0)
                        {
                            continue;
                        }
                        //sub_group不属于vin
                        if (!subgroupBelongToVin)
                        {
                            item.belongToVin = false;
                            continue;
                        }

                        string notes = item.notes;
                        bool tmpRes = CheckNotes(vinInfo, notes);
                        if (!tmpRes)
                        {
                            item.belongToVin = false;
                        }
                    }
                }
            }

            IEnumerable<Query_SubGroupResult> refSubGroups = new List<Query_SubGroupResult>();

            var refSubGroupIds = result.Where(e => e.refSubGroupId != null && e.refSubGroupId >= 0).Select(e => (int)e.refSubGroupId);
            if (refSubGroupIds != null && refSubGroupIds.Any())
            {
                refSubGroups = repository.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup_By_Ids_For_Volvo, new { subgroupIds = refSubGroupIds });
            }
            foreach (var item in result)
            {
                //跳转件
                if (item.refSubGroupId != null && item.refSubGroupId >= 0)
                {
                    var refSubGroup = refSubGroups.Where(e => e.id == item.refSubGroupId.ToString()).FirstOrDefault();
                    if (refSubGroup != null)
                    {
                        item.notes = $"参见: <a data='mainGroupId={refSubGroup.mainGroupId},subGroupId={refSubGroup.id}'>{item.partName}（{item.partCode}）</a>";
                        item.partName = "";
                        item.partCode = "";
                    }
                }
            }
        }

        string HandleInteriorCode(string notes)
        {
            if (notes.Contains("Interior code:", StringComparison.OrdinalIgnoreCase))
            {
                //处理Interior code, 将,改为| 
                //CH 178094 -, Interior code: 3303, 3703., Variant code: NF01.
                Regex interiorCodeReg = new Regex(@"Interior code:[^\.]*\.", RegexOptions.IgnoreCase);

                MatchCollection collections = interiorCodeReg.Matches(notes);
                foreach (Match mch in collections)
                {
                    string originVal = mch.Value.Trim();
                    string newVal = originVal.Replace(",", "|");
                    notes = notes.Replace(originVal, newVal);
                }
            }
            return notes;
        }

        string _marketList = "CN|EG|EU|OS|CA|US|TW|KR|GB|JP";
        string HandleMarket(string notes)
        {
            Regex marketReg = new Regex($@"\(({_marketList})\)\s*,\s*\(({_marketList})\)", RegexOptions.IgnoreCase);

            var collections = marketReg.Matches(notes);
            while (collections != null && collections.Count > 0)
            {
                foreach (Match mch in collections)
                {
                    string originVal = mch.Value.Trim();
                    string newVal = originVal.Replace(",", "|");
                    notes = notes.Replace(originVal, newVal);
                }
                collections = marketReg.Matches(notes);
            }
            return notes;
        }

        string HandleFc(string notes)
        {
            Regex fcReg = new Regex(@"FC\s([a-z]|[A-Z]|[0-9])+\s*,\s*FC\s([a-z]|[A-Z]|[0-9])+", RegexOptions.IgnoreCase);
            var collections = fcReg.Matches(notes);
            while (collections != null && collections.Count > 0)
            {
                foreach (Match mch in collections)
                {
                    string originVal = mch.Value.Trim();
                    string newVal = originVal.Replace(",", "|");
                    notes = notes.Replace(originVal, newVal);
                }
                collections = fcReg.Matches(notes);
            }
            return notes;
        }

        string HandleVariantCode(string notes)
        {
            Regex variantCodeReg = new Regex(@"Variant code:\s([a-z]|[A-Z]|[0-9]|\.|\s)+\s*,\s*Variant code:\s([a-z]|[A-Z]|[0-9]|\.|\s)+", RegexOptions.IgnoreCase);
            var collections = variantCodeReg.Matches(notes);
            while (collections != null && collections.Count > 0)
            {
                foreach (Match mch in collections)
                {
                    string originVal = mch.Value.Trim();

                    List<string> newCodes = new List<string>();
                    string[] arr = originVal.Split(",");
                    foreach (var item in arr)
                    {
                        string code = item.Replace("Variant code:", "", StringComparison.OrdinalIgnoreCase).Trim().Trim('.');
                        newCodes.Add(code);
                    }
                    string newVal = "Variant code: " + string.Join(" or ", newCodes);
                    notes = notes.Replace(originVal, newVal);
                }
                collections = variantCodeReg.Matches(notes);
            }
            return notes;
        }
        bool CheckNotes(dynamic vinInfo, string notes)
        {
            bool result = false;
            if (string.IsNullOrEmpty(notes))
            {
                result = true;
            }
            else
            {
                //interior code处理
                notes = HandleInteriorCode(notes);
                //market处理
                notes = HandleMarket(notes);
                //fc处理
                notes = HandleFc(notes);
                //variant code 处理
                notes = HandleVariantCode(notes);

                if (ContainFilterContent(notes))
                {
                    List<string> orFeatureIdList = notes.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                    foreach (var orItem in orFeatureIdList)
                    {
                        if (ContainFilterContent(orItem))
                        {
                            List<string> andFeatureIdList = orItem.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                            bool andBoolRes = true;
                            foreach (var andItem in andFeatureIdList)
                            {
                                if (ContainFilterContent(andItem))
                                {
                                    string tmpFeature = andItem.Trim().Trim('.');

                                    if (tmpFeature.StartsWith("EXC ", StringComparison.OrdinalIgnoreCase))
                                    {
                                        tmpFeature = tmpFeature.Replace("EXC ", "", StringComparison.OrdinalIgnoreCase).Trim();
                                        andBoolRes = !CheckAndCondition(vinInfo, tmpFeature);
                                    }
                                    else
                                    {
                                        andBoolRes = CheckAndCondition(vinInfo, tmpFeature);
                                    }
                                }

                                if (!andBoolRes)
                                {
                                    break;
                                }
                            }
                            if (andBoolRes)
                            {
                                result = true;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    result = true;
                }
            }
            return result;
        }
        bool CheckAndCondition(dynamic vinInfo, string tmpFeature)
        {
            bool andBoolRes = true;
            //interior code
            string vinInteriorCode = vinInfo.seatCode;
            if (tmpFeature.StartsWith("Interior code:", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinInteriorCode))
            {
                bool interiorCheck = InteriorCheck(vinInteriorCode, tmpFeature);
                if (!interiorCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //chassis
            string vinChassis = vinInfo.chassis;
            if (tmpFeature.StartsWith("CH ", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinChassis))
            {
                bool chassisCheck = ChassisCheck(vinChassis, tmpFeature);
                if (!chassisCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //FC
            string vinFc = vinInfo.manufacturerCode;
            if (tmpFeature.StartsWith("FC ", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinFc))
            {
                bool fcCheck = FcCheck(vinFc, tmpFeature);
                if (!fcCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //Variant code
            string vinTechInfo = vinInfo.techInfo;
            if (tmpFeature.StartsWith("Variant code:", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinTechInfo))
            {
                bool variantCodeCheck = VariantCodeCheck(vinTechInfo, tmpFeature);
                if (!variantCodeCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //Engine code
            string vinengineCode = vinInfo.engineCode;
            if (tmpFeature.StartsWith("ENG ", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinengineCode))
            {
                bool engineCodeCheck = EnginCodeCheck(vinengineCode, tmpFeature);
                if (!engineCodeCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //Colour code
            string vinColourCode = vinInfo.colorCode;
            if (tmpFeature.StartsWith("Colour code:", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(vinColourCode))
            {
                bool colourCodeCheck = ColourCodeCheck(vinColourCode, tmpFeature);
                if (!colourCodeCheck)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //engine
            string vinEngine = vinInfo.engine;
            //new Regex(@"[B|D|E]([0-9]|[a-z]|[A-Z]|\s|\(|\)|\.)+", RegexOptions.IgnoreCase).IsMatch(tmpFeature);
            if (!string.IsNullOrEmpty(vinEngine) && StartWithEngine(tmpFeature))
            {
                if (tmpFeature != vinEngine)
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            //maerket
            string vinMarket = vinInfo.country;
            if (!string.IsNullOrEmpty(vinMarket) && StartWithMarket(tmpFeature))
            {
                if (!tmpFeature.Contains(vinMarket))
                {
                    andBoolRes = false;
                }
                return andBoolRes;
            }
            return andBoolRes;
        }

        #region 检查remark
        bool ContainFilterContent(string notes)
        {
            bool result = false;
            if (notes.Contains("Interior code:", StringComparison.OrdinalIgnoreCase) || notes.Contains("CH ", StringComparison.OrdinalIgnoreCase) || notes.Contains("Variant code:", StringComparison.OrdinalIgnoreCase) || notes.Contains("FC ", StringComparison.OrdinalIgnoreCase) || notes.Contains("ENG ", StringComparison.OrdinalIgnoreCase) || notes.Contains("Colour code:", StringComparison.OrdinalIgnoreCase) || ContainEngine(notes) || ContainMarket(notes))
            {
                result = true;
            }
            return result;
        }

        bool ContainEngine(string input)
        {
            bool result = false;
            Regex engineReg = new Regex(@"(B3|B4|B5|B6|B8|D4|D5|D8|D9|E4)([0-9]|[a-z]|[A-Z]|\s|\(|\)|\.)+", RegexOptions.IgnoreCase);
            result = engineReg.IsMatch(input);
            return result;
        }

        bool StartWithEngine(string input)
        {
            bool result = false;
            Regex engineReg = new Regex(@"^(B3|B4|B5|B6|B8|D4|D5|D8|D9|E4)([0-9]|[a-z]|[A-Z]|\s|\(|\)|\.)+", RegexOptions.IgnoreCase);
            var collections = engineReg.Matches(input);
            if (collections != null && collections.Count == 1)
            {
                result = true;
            }
            return result;
        }
        bool ContainMarket(string input)
        {
            bool result = false;
            Regex marketReg = new Regex($@"\(({_marketList})\)\s*\|?", RegexOptions.IgnoreCase);
            result = marketReg.IsMatch(input);
            return result;
        }
        bool StartWithMarket(string input)
        {
            bool result = false;
            Regex marketReg = new Regex($@"^\(({_marketList})\)\s*\|?", RegexOptions.IgnoreCase);
            var collections = marketReg.Matches(input);
            if (collections != null && collections.Count == 1)
            {
                result = true;
            }
            return result;
        }

        //CH 178094-, Interior code: 3303, 3703., Variant code: NF01.
        bool InteriorCheck(string vinInteriorCode, string interIorCode)
        {
            bool result = false;
            string preVinInteriorCode = vinInteriorCode.Substring(0, 4);
            string[] interiorCodeValues = interIorCode.Replace("Interior code:", "", StringComparison.OrdinalIgnoreCase).Split("|", StringSplitOptions.RemoveEmptyEntries);

            if (interiorCodeValues != null || interiorCodeValues.Length > 0)
            {
                foreach (var interiorCodeValueItem in interiorCodeValues)
                {
                    string interiorCodeValueItemTrim = interiorCodeValueItem.Trim();
                    if (!interiorCodeValueItemTrim.Length.Equals(preVinInteriorCode.Length))
                    {
                        continue;
                    }

                    bool positionCheck = true;
                    for (int i = 0; i < interiorCodeValueItemTrim.Length; i++)
                    {
                        if (interiorCodeValueItemTrim[i] != preVinInteriorCode[i] && interiorCodeValueItemTrim[i] != 'X')
                        {
                            positionCheck = false;
                            break;
                        }
                    }
                    if (positionCheck)
                    {
                        result = true;
                        break;
                    }
                }
            }
            return result;
        }

        //CH 178094-, Interior code: 3301, 3701.
        bool ChassisCheck(string vinChassisCode, string chassis)
        {
            bool result = false;

            int vinChassisCodeInt = 0;
            int.TryParse(vinChassisCode, out vinChassisCodeInt);

            chassis = chassis.Replace("CH ", "", StringComparison.OrdinalIgnoreCase);

            int lineIdx = chassis.IndexOf('-');
            //-178094
            if (lineIdx == 0)
            {
                string pChassis = chassis.Substring(1);

                int pChassisInt = 0;
                int.TryParse(pChassis, out pChassisInt);

                if (pChassisInt >= vinChassisCodeInt)
                {
                    result = true;
                }
            }
            //168012-
            else if (lineIdx == chassis.Length - 1)
            {
                string pChassis = chassis.Substring(0, chassis.Length - 1);

                int pChassisInt = 0;
                int.TryParse(pChassis, out pChassisInt);

                if (pChassisInt <= vinChassisCodeInt)
                {
                    result = true;
                }
            }
            else
            {
                //168012-178094
                string startChassis = chassis.Substring(0, lineIdx);
                int startChassisInt = 0;
                int.TryParse(startChassis, out startChassisInt);

                string endChassis = chassis.Substring(lineIdx + 1);
                int endChassisInt = 0;
                int.TryParse(endChassis, out endChassisInt);
                if (startChassisInt <= vinChassisCodeInt && endChassisInt >= vinChassisCodeInt)
                {
                    result = true;
                }
            }

            return result;
        }

        bool FcCheck(string vinFc, string fc)
        {
            bool result = false;
            fc = fc.Replace("FC ", "", StringComparison.OrdinalIgnoreCase);
            if (fc.Contains(vinFc))
            {
                result = true;
            }
            return result;
        }

        bool VariantCodeCheck(string vinTechInfo, string variantCode)
        {
            bool result = false;
            List<string> vinMinorFeatureList = GetVinMinorFeatures(vinTechInfo);
            ISet<string> vinMinorFeatures = new HashSet<string>(vinMinorFeatureList);

            variantCode = variantCode.Replace("Variant code:", "", StringComparison.OrdinalIgnoreCase).Trim();
            //AG01 and (G301 or G302 or GA02 or CI01)
            //AG01+(G301;G302;GA02;GI01)
            variantCode = variantCode.Replace("and", "+", StringComparison.OrdinalIgnoreCase).Replace("or", ";", StringComparison.OrdinalIgnoreCase).Replace(" ", "");
            UCString uCString = new UCString(variantCode, '+', '-', ';');
            if (uCString.IsMatch(vinMinorFeatures))
            {
                result = true;
            }

            return result;
        }

        //ENG -3887615, EXC (CN)
        bool EnginCodeCheck(string vinEngineCode, string engineCode)
        {
            bool result = false;
            //取后7位
            vinEngineCode = vinEngineCode.Substring(vinEngineCode.Length - 7);

            engineCode = engineCode.Replace("ENG ", "", StringComparison.OrdinalIgnoreCase).Trim();

            int lineIdx = engineCode.IndexOf('-');
            //-178094
            if (lineIdx == 0)
            {
                string pEngineCode = engineCode.Substring(1);
                if (pEngineCode.CompareTo(vinEngineCode) >= 0)
                {
                    result = true;
                }
            }
            //168012-
            else if (lineIdx == engineCode.Length - 1)
            {
                string pEngineCode = engineCode.Substring(0, engineCode.Length - 1);
                if (pEngineCode.CompareTo(vinEngineCode) <= 0)
                {
                    result = true;
                }
            }
            else
            {
                //168012-178094
                string startEnginCode = engineCode.Substring(0, lineIdx);
                string endEngineCode = engineCode.Substring(lineIdx + 1);
                if (startEnginCode.CompareTo(vinEngineCode) <= 0 && endEngineCode.CompareTo(vinEngineCode) >= 0)
                {
                    result = true;
                }
            }

            return result;
        }

        //2x9 ml, Colour code: 189/199, N CHINA
        bool ColourCodeCheck(string vinColorCode, string colourCode)
        {
            bool result = false;
            vinColorCode = vinColorCode.Substring(0, 3);
            string[] colourCodeList = colourCode.Replace("Colour code:", "", StringComparison.OrdinalIgnoreCase).Split("/", StringSplitOptions.RemoveEmptyEntries);

            if (colourCodeList != null || colourCodeList.Length > 0)
            {
                foreach (var colourCodeItem in colourCodeList)
                {
                    string colourCodeListTrim = colourCodeItem.Trim();
                    if (colourCodeListTrim == vinColorCode)
                    {
                        result = true;
                        break;
                    }
                }
            }
            return result;
        }


        #endregion

        public override object QueryPartDetail(DbRESTFulRepository repository, JObject param)
        {
            param.RemoveEmptyValues();
            var brandCode = param.Value<string>(ParamFields._brandCode);
            var partId = param.Value<string>(ParamFields._partId);
            var partCode = param.Value<string>(ParamFields._partCode);
            dynamic data = null;

            if (string.IsNullOrEmpty(partId))
            {
                data = repository.Invoke(CSIs.Get_Part_Detail_Standard, new { partCode, brandCode });
            }
            else
            {
                data = repository.Invoke(CSIs.Get_Usage_Detail_Standard, param);
            }
            if (data == null) return null;
            // 1、基本信息赋值
            Query_Part_DetailResult result = JObject.FromObject(data).ToObject<Query_Part_DetailResult>();

            result.replacements = new List<Query_Part_DetailResult._replacement>();
            //3.替换件处理
            if (!string.IsNullOrEmpty(data.replacementPartNo))
            {
                List<Query_Part_DetailResult._replacement> replacements = repository.Invoke<Query_Part_DetailResult._replacement>(CSIs.Query_Parts_By_Codes, new { partCodes = data.replacementPartNo.Split(',') });
                var replacement = replacements.FirstOrDefault();
                if (replacement != null)
                {
                    replacement.brandCode = brandCode;
                    replacement.brandName = BrandDictionary.GetName(brandCode);
                    result.replacements.Add(replacement);
                }
            }
            //4.配件附加属性处理
            var props = new List<Query_Part_DetailResult._prop>
            {
                new Query_Part_DetailResult._prop { key = "件数", value = result.quantity ?? string.Empty },
            };
            result.props = props.Where(q => !string.IsNullOrEmpty(q.value)).ToList();
            return result;
        }

        protected override dynamic GetModelsByPart(DbRESTFulRepository repository, int pageIndex, int pageSize, string brandCode, string partCode)
        {
            return repository.Invoke(CSIs.Query_Models_By_Part_For_Volvo, new { pageIndex, pageSize, brandCode, partCode });
        }

        public override object QueryModel(DbRESTFulRepository repository, JObject param)
        {
            Get_Model_InfoParam modelParam = param.ToObject<Get_Model_InfoParam>();
            Get_Model_InfoResult result = new Get_Model_InfoResult();
            if (!string.IsNullOrEmpty(modelParam.vin))
            {
                var vin = QueryVinByCode(repository, modelParam);
                if (vin == null)
                {
                    throw new LogicalException($"未找到该Vin码:{modelParam.vin}", 610);
                }
                result = BuildVinResult(vin);
                result.props = GetVinProps(repository, vin);
                result.features = GetVinFeatures(repository, vin);
            }
            else
            {
                var ids = modelParam.id.Split("_");
                if (ids.Count() > 1)
                {
                    modelParam.id = ids[1];
                }
                var model = repository.Invoke(CSIs.Get_Model, modelParam);
                if (model != null)
                {
                    result = JObject.FromObject(model).ToObject<Get_Model_InfoResult>();
                    result.props = GetModelProps(repository, param);
                }
            }
            return result;
        }

        protected override dynamic QueryVinByCode(DbRESTFulRepository repository, Get_Model_InfoParam param)
        {
            return repository.Invoke(CSIs.Query_Vin_By_Code_For_Volvo, param);
        }
        public override object OnlineQueryVin(DbRESTFulRepository repository, JObject param)
        {
            Get_Model_InfoParam modelParam = param.ToObject<Get_Model_InfoParam>();
            Get_Model_InfoResult result = new Get_Model_InfoResult();

            object vinInfo = null;

            HandleEpcOnlineVin(modelParam, repository);
            vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Volvo, param);
            if (vinInfo == null)
            {
                throw new LogicalException($"未找到该Vin码{modelParam.vin}", 610);
            }
            result = BuildVinResult(vinInfo);
            result.props = GetVinProps(repository, vinInfo);
            result.features = GetVinFeatures(repository, vinInfo);
            return result;
        }

        protected override List<Get_Model_InfoResult._props> GetVinProps(DbRESTFulRepository repository, dynamic vinInfo)
        {
            var props = new List<Get_Model_InfoResult._props>();
            props.Add(new Get_Model_InfoResult._props { key = "车型年份", value = vinInfo.modelYear });
            props.Add(new Get_Model_InfoResult._props { key = "高速并联稳压单位", value = vinInfo.vehicleStatus });
            props.Add(new Get_Model_InfoResult._props { key = "工厂代码", value = vinInfo.manufacturerCode });
            props.Add(new Get_Model_InfoResult._props { key = "转向齿轮生产编号", value = vinInfo.steeringWheelCode });
            props.Add(new Get_Model_InfoResult._props { key = "建构周", value = vinInfo.productionDate });
            props.Add(new Get_Model_InfoResult._props { key = "类型", value = vinInfo.modelType });
            props.Add(new Get_Model_InfoResult._props { key = "底盘", value = vinInfo.chassis });
            props.Add(new Get_Model_InfoResult._props { key = "合作伙伴组", value = vinInfo.market });
            props.Add(new Get_Model_InfoResult._props { key = "椅套/内装代码", value = vinInfo.seatCode });
            props.Add(new Get_Model_InfoResult._props { key = "汽车座椅", value = vinInfo.seat });
            props.Add(new Get_Model_InfoResult._props { key = "外观颜色", value = vinInfo.colorCode });
            props.Add(new Get_Model_InfoResult._props { key = "外观颜色", value = vinInfo.color });
            props.Add(new Get_Model_InfoResult._props { key = "车身款式代码", value = vinInfo.bodyCode });
            props.Add(new Get_Model_InfoResult._props { key = "车身款式", value = vinInfo.body });
            props.Add(new Get_Model_InfoResult._props { key = "特殊车辆代码", value = vinInfo.carCode });
            props.Add(new Get_Model_InfoResult._props { key = "特殊车辆", value = vinInfo.carName });
            props.Add(new Get_Model_InfoResult._props { key = "销售类型", value = vinInfo.saleCode });
            props.Add(new Get_Model_InfoResult._props { key = "销售类型", value = vinInfo.sale });
            props.Add(new Get_Model_InfoResult._props { key = "市场代码", value = vinInfo.countryCode });
            props.Add(new Get_Model_InfoResult._props { key = "市场", value = vinInfo.country });
            props.Add(new Get_Model_InfoResult._props { key = "发动机代码", value = vinInfo.engineType });
            props.Add(new Get_Model_InfoResult._props { key = "发动机", value = vinInfo.engine });
            props.Add(new Get_Model_InfoResult._props { key = "发动机零件号码", value = vinInfo.engineNum });
            props.Add(new Get_Model_InfoResult._props { key = "发动机序号", value = vinInfo.engineCode });
            props.Add(new Get_Model_InfoResult._props { key = "变速器代码", value = vinInfo.transmissionType });
            props.Add(new Get_Model_InfoResult._props { key = "变速箱", value = vinInfo.transmission });
            props.Add(new Get_Model_InfoResult._props { key = "变速箱零件号码", value = vinInfo.transmissionNum });
            props.Add(new Get_Model_InfoResult._props { key = "齿轮箱序号", value = vinInfo.transmissionCode });
            props.Add(new Get_Model_InfoResult._props { key = "底盘代码", value = vinInfo.chassisCode });
            return props;
        }

        protected override List<Get_Model_InfoResult._features> GetVinFeatures(DbRESTFulRepository repository, dynamic vinInfo)
        {
            var features = new List<Get_Model_InfoResult._features>();
            if (vinInfo.techInfo != null && !string.IsNullOrEmpty(vinInfo.techInfo))
            {
                JArray jarr = JsonConvert.DeserializeObject<JArray>(vinInfo.techInfo);
                if (jarr != null && jarr.Any())
                {
                    foreach (var item in jarr)
                    {
                        string key = item["key"].ToObject<string>();
                        string value = item["value"].ToObject<string>();
                        features.Add(new Get_Model_InfoResult._features { key = key, value = value });
                    }
                }
            }
            return features;
        }

        protected override List<Query_SubGroupResult> FilterSubGroupsByVin(DbRESTFulRepository repository, List<Query_SubGroupResult> results, JObject param)
        {
            var vin = param.Value<string>(ParamFields._vin);
            if (string.IsNullOrEmpty(vin) || results == null || results.Count == 0)
            {
                return results;
            }
            var vinInfo = repository.Invoke(CSIs.Query_Vin_By_Code_For_Volvo, new { vin });
            if (vinInfo != null)
            {
                foreach (var info in results)
                {
                    bool belongTo = CheckSubGroupBelongToByApplcableModel(vinInfo, info);
                    if (belongTo)
                    {
                        belongTo = CheckNotes(vinInfo, info.remark);
                    }

                    info.belongTo = belongTo;
                }
            }
            return results;
        }

        bool CheckSubGroupBelongToByApplcableModel(dynamic vinInfo, Query_SubGroupResult subgroup)
        {
            bool belongTo = false;
            string applicableModel = subgroup.applicableModel;
            if (string.IsNullOrEmpty(applicableModel))
            {
                belongTo = true;
            }
            else
            {
                List<string> orFeatureIdList = applicableModel.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                foreach (var item in orFeatureIdList)
                {
                    List<string> andFeatureIdList = item.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                    bool andBoolRes = true;
                    foreach (var andItem in andFeatureIdList)
                    {
                        var tmpFeature = andItem.Trim();
                        //engine
                        string vinEngine = vinInfo.engine;
                        if (tmpFeature.StartsWith("发动机:") && !string.IsNullOrEmpty(vinEngine))
                        {
                            bool engineCheck = EngineCheck(vinEngine, tmpFeature);
                            if (!engineCheck)
                            {
                                andBoolRes = false;
                                break;
                            }
                        }

                        //transmission
                        string vinTransmission = vinInfo.transmission;
                        if (tmpFeature.StartsWith("变速箱:") && !string.IsNullOrEmpty(vinTransmission))
                        {
                            bool transmissionCheck = TransmissionCheck(vinTransmission, tmpFeature);
                            if (!transmissionCheck)
                            {
                                andBoolRes = false;
                                break;
                            }
                        }

                        //drive type
                        string vinDriveType = vinInfo.driveType;
                        if (tmpFeature.StartsWith("转向:") && !string.IsNullOrEmpty(vinDriveType))
                        {
                            bool driveTypeCheck = DriveTypeCheck(vinDriveType, tmpFeature);
                            if (!driveTypeCheck)
                            {
                                andBoolRes = false;
                                break;
                            }
                        }
                    }
                    if (andBoolRes)
                    {
                        belongTo = true;
                        break;
                    }
                }

            }
            return belongTo;
        }

        bool EngineCheck(string vinEngine, string engine)
        {
            bool result = false;
            engine = engine.Replace("发动机:", "").Trim();
            if (vinEngine.Contains(engine))
            {
                result = true;
            }
            return result;
        }

        bool TransmissionCheck(string vinTransmission, string transmission)
        {
            bool result = false;
            transmission = transmission.Replace("变速箱:", "").Trim();
            if (vinTransmission.Contains(transmission))
            {
                result = true;
            }
            return result;
        }

        bool DriveTypeCheck(string vinDriveType, string driveType)
        {
            bool result = false;
            driveType = driveType.Replace("转向:", "").Trim();
            if (vinDriveType.Equals(driveType))
            {
                result = true;
            }
            return result;
        }

        List<string> GetVinMinorFeatures(string techInfo)
        {
            List<string> vinFeatureList = new List<string>();
            if (!string.IsNullOrEmpty(techInfo))
            {
                JArray jarr = JsonConvert.DeserializeObject<JArray>(techInfo);
                if (jarr != null && jarr.Any())
                {
                    foreach (var item in jarr)
                    {
                        string key = item["key"].ToObject<string>();
                        vinFeatureList.Add(key);
                    }
                }
            }
            return vinFeatureList;
        }

        public void HandleEpcOnlineVin(Get_Model_InfoParam param, DbRESTFulRepository repository)
        {
            string vin = param.vin;
            string brandCode = param.brandCode;

            EPCOnlineQueryService epcOnlineQueryService = new EPCOnlineQueryService();
            var queryRes = epcOnlineQueryService.QueryVin(vin, brandCode);

            VolvoVinModel vinInfo = null;
            CheckOnlineVinQueryRes(queryRes, vin, out vinInfo);

            if (vinInfo != null)
            {
                vinInfo.vinCode = vin;
                vinInfo.createtime = DateTime.Now;
                repository.Invoke(CSIs.Insert_Vin_For_Volvo, vinInfo);
            }
        }
        //{hasError: false, errorMessage: '', data: {vin: task.params.vin, result01: rst, result02: rst01}}
        void CheckOnlineVinQueryRes(JObject queryRes, string vin, out VolvoVinModel vinInfoOut)
        {
            if (queryRes == null)
            {
                LoggerManager.Logger.LogError("VolvoQueryInterceptor.GetEpcOnlineVin, queryRes is null");

                throw new Exception($"系统繁忙，请稍后再试！({vin})");
            }
            bool hasError = queryRes["HasError"].ToObject<bool>();
            if (hasError)
            {
                string errMsg = queryRes["ErrorMessage"].ToObject<string>();
                LoggerManager.Logger.LogError($"VolvoQueryInterceptor.GetEpcOnlineVin, hasError,{errMsg} ");

                throw new Exception($"系统繁忙，请稍后再试！({vin})");
            }
            var data = queryRes["Data"];
            if (data == null)
            {
                LoggerManager.Logger.LogError("VolvoQueryInterceptor.GetEpcOnlineVin, data is null");

                throw new Exception($"系统繁忙，请稍后再试！({vin})");
            }
            var resultInfo = data["result"];
            if (resultInfo == null)
            {
                LoggerManager.Logger.LogError("VolvoQueryInterceptor.GetEpcOnlineVin, result is null");

                throw new Exception($"系统繁忙，请稍后再试！({vin})");
            }
            var vinInfo = resultInfo["general"];
            if (vinInfo == null)
            {
                LoggerManager.Logger.LogError("VolvoQueryInterceptor.GetEpcOnlineVin, general is null");

                throw new Exception($"系统繁忙，请稍后再试！({vin})");
            }
            JArray vinJarr = JArray.FromObject(vinInfo);

            vinInfoOut = GetVinInfo(vinJarr);

            var techInfo = resultInfo["variDesign"];
            if (techInfo != null)
            {
                vinInfoOut.techInfo = JsonConvert.SerializeObject(techInfo);
            }
        }

        string _lhd = "L.H.D";
        VolvoVinModel GetVinInfo(JArray vinKeyValues)
        {
            VolvoVinModel result = null;
            if (vinKeyValues != null && vinKeyValues.Any())
            {
                result = new VolvoVinModel();
                int colorIdx = 0;
                int saleIdx = 0;
                foreach (var item in vinKeyValues)
                {
                    string key = item["key"].ToObject<string>();
                    string value = item["value"].ToObject<string>();

                    if (key == "车型年份")
                    {
                        result.modelYear = value;
                    }
                    else if (key == "车型")
                    {
                        result.modelName = value;
                    }
                    else if (key == "高速并联稳压单位")
                    {
                        result.vehicleStatus = value;
                    }
                    else if (key == "工厂代码")
                    {
                        result.manufacturerCode = value;
                    }
                    else if (key == "转向齿轮生产编号")
                    {
                        result.steeringWheelCode = value;
                    }
                    else if (key == "建构周")
                    {
                        result.productionDate = value;
                    }
                    else if (key == "类型")
                    {
                        result.modelType = value;
                    }
                    else if (key == "底盘")
                    {
                        result.chassis = value;
                    }
                    else if (key == "合作伙伴组")
                    {
                        result.market = value;
                    }
                    else if (key == "椅套/内装代码")
                    {
                        result.seatCode = value;
                    }
                    else if (key == "汽车座椅")
                    {
                        result.seat = value;
                    }
                    else if (key == "外观颜色")
                    {
                        if (colorIdx == 0)
                        {
                            result.colorCode = value;
                        }
                        else
                        {
                            result.color = value;
                        }
                        colorIdx++;
                    }
                    else if (key == "车身款式代码")
                    {
                        result.bodyCode = value;
                    }
                    else if (key == "车身款式")
                    {
                        result.body = value;
                    }
                    else if (key == "特殊车辆代码")
                    {
                        result.carCode = value;
                    }
                    else if (key == "特殊车辆")
                    {
                        result.carName = value;
                    }
                    else if (key == "销售类型")
                    {
                        if (saleIdx == 0)
                        {
                            result.saleCode = value;
                        }
                        else
                        {
                            result.sale = value;
                        }
                        saleIdx++;
                    }
                    else if (key == "市场代码")
                    {
                        result.countryCode = value;
                    }
                    else if (key == "市场")
                    {
                        result.country = value;
                        if (value.Equals("CN", StringComparison.OrdinalIgnoreCase))
                        {
                            result.driveType = _lhd;
                        }
                    }
                    else if (key == "发动机代码")
                    {
                        result.engineType = value;
                    }
                    else if (key == "发动机")
                    {
                        result.engine = value;
                    }
                    else if (key == "发动机零件号码")
                    {
                        result.engineNum = value;
                    }
                    else if (key == "发动机序号")
                    {
                        result.engineCode = value;
                    }
                    else if (key == "变速器代码")
                    {
                        result.transmissionType = value;
                    }
                    else if (key == "变速箱")
                    {
                        result.transmission = value;
                    }
                    else if (key == "变速箱零件号码")
                    {
                        result.transmissionNum = value;
                    }
                    else if (key == "齿轮箱序号")
                    {
                        result.transmissionCode = value;
                    }
                    else if (key == "底盘代码")
                    {
                        result.chassisCode = value;
                    }
                }
            }
            return result;
        }

        protected override List<QuickPartResult> QuickQueryPartsFilterByUsage_Vin(DbRESTFulRepository repository, List<QuickPartResult> parts, int selectorId, string vin)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            if (!string.IsNullOrEmpty(vin) && parts != null && parts.Any())
            {
                List<string> partCodes = parts.Select(e => e.partCode).Distinct().ToList();
                List<Query_PartsResult> partUsages = repository.Invoke<Query_PartsResult>(CSIs.Query_Quick_PartUsage_For_Volvo, new { selectorId, partCodes });
                if (partUsages != null && partUsages.Any())
                {
                    List<string> usedPartCodes = new List<string>();
                    var vinInfo = repository.Invoke(CSIs.Get_VinFilters_For_Volvo, new { vin });
                    if (vinInfo != null)
                    {
                        IEnumerable<int> subgroupIds = partUsages.Where(e => e.subgroupId != null && e.subgroupId > 0).Select(e => (int)e.subgroupId);
                        List<Query_SubGroupResult> subgroupList = repository.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup_By_Ids_For_Volvo, new { subgroupIds = subgroupIds });

                        foreach (var item in partUsages)
                        {
                            if (item.subgroupId != null && item.subgroupId > 0)
                            {
                                var subgroup = subgroupList.FirstOrDefault(e => e.id == item.subgroupId.ToString());
                                if (subgroup != null)
                                {
                                    bool subgroupBelongToVin = CheckSubGroupBelongToByApplcableModel(vinInfo, subgroup);
                                    //sub_group不属于vin
                                    if (!subgroupBelongToVin)
                                    {
                                        continue;
                                    }
                                }
                            }

                            string notes = item.notes;
                            bool tmpRes = CheckNotes(vinInfo, notes);
                            if (!tmpRes)
                            {
                                continue;
                            }

                            usedPartCodes.Add(item.partCode);
                        }

                        if (usedPartCodes.Any())
                        {
                            ret = parts.Where(e => usedPartCodes.Contains(e.partCode)).ToList();
                        }
                    }
                }
            }
            return ret;
        }
    }
}
